package cn.cxyxj.study110;


import cn.cxyxj.study110.a.CustomizeVoter;
import cn.cxyxj.study110.entity.SysUser;
import cn.cxyxj.study110.entity.SysUserDetails;
import cn.cxyxj.study110.impl.UserDetailsServiceImpl;
import cn.cxyxj.study110.utils.RedisUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.vote.UnanimousBased;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.expression.WebExpressionVoter;

import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

/**
 * 动态授权，该配置使用自定义 access 表达式方式
 */
@Configuration
public class SecurityConfigB extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {


        http.authorizeRequests()  //开启配置
                .antMatchers("/permitAll").permitAll() // 访问/permitAll路径，不需要登录
                .antMatchers("/denyAll").denyAll()  // 不允许访问
                .anyRequest().access("@accessDecisionService.hasPermission(request,authentication)")
                .and()
                .formLogin() // 开启表单登陆
                .successHandler((request, response, authentication) -> {
                    // 登录成功回调
                    SysUserDetails sysUserDetails = (SysUserDetails) authentication.getPrincipal();
                    SysUser sysUser = sysUserDetails.getSysUser();
                    response.setContentType("application/json;charset=utf-8");
                    PrintWriter out = response.getWriter();
                    HashMap<String, Object> result = new HashMap<>();
                    result.put("code", "200");
                    result.put("msg", "登录成功");
                    result.put("data", sysUserDetails);
                    out.write(new ObjectMapper().writeValueAsString(result));
                    // 将接口Url 保存到 Redis 中
                    Set<String> urlSet = sysUserDetails.getUrlSet();
                    for (String url : urlSet) {
                        RedisUtil.sSet(sysUser.getAccount() + ":" + sysUser.getId(), url);
                    }
                    out.flush();
                    out.close();
                });
        http.csrf().disable();


    }


    // b
    // 注册自定义的投票器（这个投票器的实现看下面）
    @Bean
    public AccessDecisionVoter<FilterInvocation> accessDecisionProcessor() {
        return new CustomizeVoter();
    }

    @Bean
    public AccessDecisionManager accessDecisionManager() {
        // 构造一个新的 AccessDecisionManager 放入两个投票器
        List<AccessDecisionVoter<?>> decisionVoters = Arrays.asList(accessDecisionProcessor(),
                new WebExpressionVoter());
        // 一票否决策略
        return new UnanimousBased(decisionVoters);
    }
}
